package com.xmutca.sso.server.web;

import com.alibaba.fastjson.JSON;
import com.xmutca.core.common.Receipt;
import com.xmutca.core.common.Result;
import com.xmutca.sso.common.util.ShiroWebUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: 彭伟煌(pengweihuang@xmutca.com)
 * @create: 2016-08-03 22:19
 */
@Controller
@RequestMapping("/login")
public class LoginController {

    @Value("${sso.server.url}")
    private String serverUrl;

    /**
     * 跳转登陆界面
     * @param req
     * @param model
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public String loginGet(HttpServletRequest req, Model model, String redirectUrl, boolean xmlHttpRequest) throws IOException {
        Subject subject = SecurityUtils.getSubject();

        if (subject.isRemembered() &&  StringUtils.isNotBlank(redirectUrl)) {
            //判断用户是否曾经登陆过
            return "redirect:" + redirectUrl;
        }

        if(subject.isAuthenticated() && StringUtils.isNotBlank(redirectUrl)) {
            //重构并且，跳转回redirect_uri
            return "redirect:" + redirectUrl;
        }

        if (subject.isAuthenticated() || subject.isRemembered()) {
            if (xmlHttpRequest) {
                Result<Object> result = new Result(Result.Status.SUCCESS, "login success!", subject.getPrincipal());
                model.addAttribute("result", JSON.toJSONString(result));
                return "json_result";
            }
            return "redirect:/index";
        }

        if (xmlHttpRequest) {
            Result<String> result = new Result<>(Result.Status.NEED_LOGIN, "请进行登陆", serverUrl);
            model.addAttribute("result", JSON.toJSONString(result));
            return "json_result";
        }

        //添加基本信息
        model.addAttribute("redirectUrl", redirectUrl);
        return "login";
    }

    /**
     * 只有登陆认证失败才会访问到该方法
     */
    @RequestMapping(method = RequestMethod.POST)
    public String loginPost(HttpServletRequest request, String username, String redirectUrl, Model model, boolean xmlHttpRequest) throws IOException {
        //如果已经登陆了，或者是记住我了走别的渠道，防止二次登陆
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated() || subject.isRemembered()) {
            return loginGet(request, model, redirectUrl, xmlHttpRequest);
        }

        String shiroLoginFailure = (String)request.getAttribute("shiroLoginFailure");

        //如果错误信息为空，说明是二次登陆操作，直接返回给login自己去处理
        if (StringUtils.isEmpty(shiroLoginFailure)) {
            return String.format("redirect:/login?username=%s&redirectUrl=%s", StringUtils.defaultString(username), StringUtils.defaultString(redirectUrl));
        }

        String message = "用户名/密码错误";
        if(UnknownAccountException.class.getName().equals(shiroLoginFailure)) {
            message = "用户名/密码错误";
        } else if(IncorrectCredentialsException.class.getName().equals(shiroLoginFailure)) {
            message = "用户名/密码错误";
        } else if(shiroLoginFailure != null) {
            message = "其他错误：" + shiroLoginFailure;
        }

        //添加基本信息
        model.addAttribute("redirectUrl", redirectUrl);
        model.addAttribute("message", message);

        if (ShiroWebUtils.isAjaxRequest(request)) {
            //设置参数信息
            Map<String, String> data = new HashMap<>();
            data.put("username", StringUtils.defaultString(username));
            data.put("redirectUrl", StringUtils.defaultString(redirectUrl));

            //返回参数信息
            Result<Map<String, String>> result = new Result<>(Result.Status.NEED_LOGIN, message, data);
            model.addAttribute("result", JSON.toJSONString(result));
            return "json_result";
        }
        return "login";
    }
}
